#include "Buffer.h"

using namespace Graphics;

RTTI_DEFINITIONS(Buffer)

#ifdef DX_11
Buffer::Buffer(void)
	:Engine::NResource("Buffer",""),
	 mBuffer(NULL),
	 mNumberOfVerts(0)
{
}

Buffer::~Buffer(void)
{
	mBuffer->Release();
	mBuffer = NULL;
}

bool Buffer::Initialize(unsigned int vertexSize, void* vertices, UINT numberOfVerts, BufferType bufferType)
{
	Graphics::D3DDevice* device = GetPlatform()->GetDevice()->As<Graphics::D3DDevice>();
	HRESULT result;
	mNumberOfVerts = numberOfVerts;
	mBufferType = bufferType;

	D3D11_BUFFER_DESC bufferDesc;
	D3D11_SUBRESOURCE_DATA bufferData;
	
	ZeroMemory( &bufferDesc, sizeof(bufferDesc) );
	bufferDesc.Usage = D3D11_USAGE_DEFAULT;
	bufferDesc.ByteWidth = vertexSize * mNumberOfVerts;
	bufferDesc.BindFlags = bufferType;
	bufferDesc.CPUAccessFlags = 0;
	bufferDesc.MiscFlags = 0;
	bufferDesc.StructureByteStride = 0;

	ZeroMemory( &bufferData, sizeof(bufferData) );
	bufferData.pSysMem = vertices;
	bufferData.SysMemPitch = 0;
	bufferData.SysMemSlicePitch = 0;

	result = device->GetDevice()->CreateBuffer( &bufferDesc, &bufferData, &mBuffer);
	CHECK(result);
	return true;
}

bool Buffer::Initialize(D3D11_BUFFER_DESC bufferDesc)
{
	Graphics::D3DDevice* device = GetPlatform()->GetDevice()->As<Graphics::D3DDevice>();
	HRESULT result;
	mNumberOfVerts = 0;
	mBufferType = (BufferType)bufferDesc.BindFlags;

	result = device->GetDevice()->CreateBuffer( &bufferDesc, NULL, &mBuffer);
	CHECK(result);
	return true;
}

bool Buffer::Initialize(D3D11_BUFFER_DESC bufferDesc, D3D11_SUBRESOURCE_DATA  data)
{
	Graphics::D3DDevice* device = GetPlatform()->GetDevice()->As<Graphics::D3DDevice>();
	HRESULT result;
	mNumberOfVerts = 0;
	mBufferType = (BufferType)bufferDesc.BindFlags;

	result = device->GetDevice()->CreateBuffer( &bufferDesc, &data, &mBuffer);
	CHECK(result);
	return true;
}


void Buffer::Render(unsigned int stride, unsigned int offset)
{
	Graphics::D3DDevice* device = GetPlatform()->GetDevice()->As<Graphics::D3DDevice>();
	// Set the vertex buffer to active in the input assembler so it can be rendered.
	switch (mBufferType)
	{
	case Graphics::VertexBuffer:
		device->GetDeviceContext()->IASetVertexBuffers(0, 1, &mBuffer, &stride, &offset);
		break;
	case Graphics::IndexBuffer:
		device->GetDeviceContext()->IASetIndexBuffer(mBuffer, DXGI_FORMAT_R32_UINT, 0);
		break;
	default:
		break;
	}
}

void Buffer::Lock()
{
}

void Buffer::Unlock()
{
}

void Buffer::Release()
{
	mBuffer->Release();
}

#elif defined( DX_9 )
Buffer::Buffer(void)
	:mMemoryPointer(NULL),
	 mNumberOfVerts(0)
{
}

Buffer::~Buffer(void)
{
}

void Buffer::Initialize(LPDIRECT3DDEVICE9 device, UINT numberOfVerts)
{
	HRESULT result;
	mNumberOfVerts = numberOfVerts;
	result = device->CreateVertexBuffer(mNumberOfVerts*sizeof(CUSTOMVERTEX),0,CUSTOMFVF,D3DPOOL_MANAGED,&mVertexBuffer,NULL);
	CHECK(result);
}

void Buffer::Render(LPDIRECT3DDEVICE9 device)
{
	HRESULT result = device->SetRenderState( D3DRS_LIGHTING, FALSE );
	CHECK(result);

	result = device->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
	CHECK(result);

	result = device->SetFVF(CUSTOMFVF);													// select which vertex format we are using
	CHECK(result);

	result = device->SetStreamSource(0, mVertexBuffer, 0, sizeof(CUSTOMVERTEX));		// select the vertex buffer to display
	CHECK(result);
}

void Buffer::Lock()
{
	HRESULT result = mVertexBuffer->Lock(0, 0, (void**)&mMemoryPointer, 0);
	CHECK(result);
}

void Buffer::Unlock()
{
	HRESULT result = mVertexBuffer->Unlock();
	CHECK(result);
}

VOID* Buffer::GetMemoryPointer()
{
	return mMemoryPointer;
}

#endif